package top.eggcode.security.session;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;
import top.eggcode.common.mvc.HttpResponseUtil;
import top.eggcode.common.mvc.ResultStatus;
import top.eggcode.common.mvc.ResultWrapper;
import top.eggcode.component.session.Session;
import top.eggcode.component.session.SessionHelper;
import top.eggcode.security.TokenRefreshException;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Title: 检查会话
 * Description: 用户必须携带登录标识
 * Date: 2021/4/17 20:05
 *
 * @author JiaQi Ding
 * @version 1.0
 */
public class AppSessionFilter extends AccessControlFilter {

    private final static long GLOBAL_SESSION_TIMEOUT = 1800L;

    /**
     * 是否允许访问
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {

        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;

        // 会话标识
        String sessionId = httpRequest.getHeader("session-id");

        if (StringUtils.isEmpty(sessionId)) {

            // 未携带Token
            HttpResponseUtil.sendJson(
                    (HttpServletResponse) servletResponse,
                    ResultWrapper.failure(ResultStatus.REQ_NO_TOKEN)
            );
            // 拒绝访问
            return false;
        }

        Session session = SessionHelper.getSessionManager().getSession(sessionId);

        String principal = null;

        // session不为空
        if (session != null) {
            principal = (String) session.getAttribute("principal");
        }
        Subject subject = getSubject(servletRequest, servletResponse);
        // 如果未认证
        if (!subject.isAuthenticated()) {
            // 认证身份
            try {
                subject.login(new UsernamePasswordToken(principal, sessionId));
            } catch (AuthenticationException e) {
                if (e instanceof IncorrectCredentialsException) {
                    // 无效token
                    HttpResponseUtil.sendJson((HttpServletResponse) servletResponse,
                            ResultWrapper.failure(ResultStatus.USER_INVALID_TOKEN));
                } else if (e instanceof ExpiredCredentialsException) {
                    // token 过期
                    HttpResponseUtil.sendJson((HttpServletResponse) servletResponse,
                            ResultWrapper.failure(ResultStatus.USER_OVERDUE_TOKEN));
                } else if (e instanceof UnknownAccountException) {
                    // 用户不存在
                    HttpResponseUtil.sendJson((HttpServletResponse) servletResponse,
                            ResultWrapper.failure(ResultStatus.USER_ACCOUNT_NOT_FOUND));
                } else if (e instanceof TokenRefreshException) {
                    // token 需要刷新
                    HttpResponseUtil.sendJson((HttpServletResponse) servletResponse,
                            ResultWrapper.failure(ResultStatus.USER_TOKEN_REFRESH));
                } else {
                    // token 过期
                    HttpResponseUtil.sendJson((HttpServletResponse) servletResponse,
                            ResultWrapper.failure(ResultStatus.USER_AUTHORIZATION_FAIL));
                }
                // 拒绝访问
                return false;
            }
        }


        return true;
    }

    /**
     * 访问拒绝后的处理（isAccessAllowed 返回 false）
     * true 让过滤链继续执行，false 请求结束
     */
    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {

        // 请求结束
        return false;
    }
}
